package com.zn.net.socket
{
    import com.zn.log.Log;
    import com.zn.net.Protocol;
    
    import flash.errors.EOFError;
    import flash.errors.IOError;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.Socket;
    import flash.net.registerClassAlias;
    import flash.utils.ByteArray;
    import flash.utils.Endian;

    /**
     *socket 通信
     * @author 朱能
     *
     */
    public class ClientSocket extends EventDispatcher
    {
        public static const HEADER_SIZE:Number = 18;

        private var _socket:Socket;

        private static var _instance:ClientSocket;

        private var _readBuffer:ByteArray;

        private var _readOffset:int;

        private var _writeOffset:int;

        public function ClientSocket()
        {
			registerClassAlias("com.zn.net.socket.SocketPackageIn",SocketPackageIn);
        }

        public static function get instance():ClientSocket
        {
            if (!_instance)
                _instance = new ClientSocket();

            return _instance;
        }

        public function connectServer(ip:String, port:int):void
        {
            if (!_socket)
            {
                _socket = new Socket();
                _socket.addEventListener(Event.CONNECT, connectHandler);
                _socket.addEventListener(ProgressEvent.SOCKET_DATA, reciveDataHandler);
                _socket.addEventListener(Event.CLOSE, closeHandler);
                _socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
                _socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);

                _socket.connect(ip, port);
            }
        }


        /**
         *关闭连接
         *
         */
        public function close():void
        {
            if (!_socket)
                return;
            _socket.close();

            _socket.removeEventListener(Event.CONNECT, connectHandler);
            _socket.removeEventListener(ProgressEvent.SOCKET_DATA, reciveDataHandler);
            _socket.removeEventListener(Event.CLOSE, closeHandler);
            _socket.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            _socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);

            _socket = null;

        }

        /**
         *是否连接成功
         * @return
         *
         */
        public function get connected():Boolean
        {
            if (_socket)
                return _socket.connected;
            else
                return false;
        }

        private function connectHandler(event:Event):void
        {
            Log.debug(ClientSocket, "connectHandler", "服务器连接成功");
            dispatchEvent(event);
        }

        /**
         *接收到数据
         * @param event
         *
         */
        private function reciveDataHandler(event:ProgressEvent):void
        {
            if (_socket.bytesAvailable > 0)
            {
                var len:int = _socket.bytesAvailable;
                _socket.readBytes(_readBuffer, _writeOffset, _socket.bytesAvailable);
                _writeOffset += len;
                if (_writeOffset > 1)
                {
                    _readBuffer.position = 0;
                    _readOffset = 0;
                    if (_readBuffer.bytesAvailable >= HEADER_SIZE)
                    {
                        readPackage();
                    }
                }
            }

            dispatchEvent(event.clone());
        }

        private function readPackage():void
        {
            do
            {
                var len:int = _readBuffer.readShort(); //读取数据长度	
                var dataLeft:int = _writeOffset - _readOffset;
                if (dataLeft >= len && len != 0)
                {
                    _readBuffer.position = _readOffset;
                    var buff:SocketPackageIn = new SocketPackageIn();
                    buff.load(_readBuffer, len);

                    _readOffset += len;
                    dataLeft = _writeOffset - _readOffset;
                    handlePackage(buff);
                }
                else
                {
                    break;
                }
            } while (dataLeft >= HEADER_SIZE);

            _readBuffer.position = 0;
            if (dataLeft > 0)
            {
                _readBuffer.writeBytes(_readBuffer, _readOffset, dataLeft);
            }
            _readOffset = 0;
            _writeOffset = dataLeft;
        }

        private function handlePackage(pkg:SocketPackageIn):void
        {
            try
            {
                if (pkg.isCheckPass)
                {
                    //执行协议方法
                    var callFunctionList:Vector.<Function> = Protocol.getProtocolFunctionList(pkg.code);
                    var funBy:SocketPackageIn;
					
					var c:ByteArray=new ByteArray();
					
					pkg.position=0;
					c.writeObject(pkg);
					
                    for each (var callFun:Function in callFunctionList)
                    {
                        //克隆流
						funBy=SocketPackageIn(c.readObject());
                        //调用方法
                        callFun(funBy);
                    }
                }
                else
                {
                    //trace("pkg checksum error:",ByteUtils.ToHexDump("Bytes Left:",pkg,0,pkg.length));
                    trace("pkg checksum error:收到：", pkg.checkSum.toString(), "计算：", pkg.calculateCheckSum().toString());
                }
            }
            catch (err:Error)
            {
                trace("handlePackage:", err.getStackTrace());
                    //trace(ByteUtils.ToHexDump("Bytes Left:",_readBuffer,_readOffset,_readBuffer.bytesAvailable));
            }
        }

        /**
         *关闭连接 事件
         * @param event
         *
         */
        private function closeHandler(event:Event):void
        {
            Log.debug(ClientSocket, "closeHandler", "服务器连接断开");
            dispatchEvent(event);
        }

        private function ioErrorHandler(event:IOErrorEvent):void
        {
            close();
            dispatchEvent(event);
            throw new IOError("socket io 错误");
        }

        private function securityErrorHandler(event:SecurityErrorEvent):void
        {
            close();
            dispatchEvent(event);
            throw new SecurityError("socket 安全错误");
        }

        /**
         *发送消息
         * @param commandId 协议
         * @param by 数据
         * @return
         *
         */
        public static function sendMessage(sendPkg:SocketPackageOut):Boolean
        {
            if (instance.connected)
            {
                sendPkg.pack();
                //发送包
                instance._socket.writeBytes(sendPkg, 0, sendPkg.length);
                instance._socket.flush();

                Log.debug(ClientSocket, "sendMessage", "发送协议 ： " + sendPkg.code.toString(16));
                return true;
            }
            return false;
        }
    }
}